﻿using System;
using DamageNumbersPro;
using Gp.Scripts.Core;
using Gp.Scripts.GUI;
using Gp.Scripts.GUI.VFX;
using MoreMountains.Feedbacks;
using QFramework;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Serialization;

namespace Gp.Scripts.Core {
    public class FeedBackPlayer : MonoBehaviour {
        public GeneralFxPlayer generalPlayer;

        [Title("效果")]
        public MMFeedbacks deathFeedback;
        public MMFeedbacks armorBreakFeedback;

        [FormerlySerializedAs("hitFeedback")] public MMF_Player hitLightFeedback;
        public MMF_Player hitHeavyFeedback;
        
        public MMF_Player blockAttackFeedback;


        // public MMF_Player onUnitSelectFeedback;
        public MMF_Player onMeleeTakeout;
        public MMF_Player onRangeTakeout;
        
        

        [Title("跳字效果")] public FloatingText damageFeedback;
        public FloatingText healthDamageFeedback;
        public FloatingText electricDamage;
        public FloatingText acidDamage;
        public FloatingText fireDamage;
        

        public DamageNumber armorBreak;
        public DamageNumber attackMiss;
        public DamageNumber critical;

        private void DamageFeedback(UnitAttackResultEvent e) {
            if (!e.Target) return;
            var pos = e.Target.transform.position;

            // 未命中反馈
            if (!e.Result.IsHit) {
                attackMiss.Spawn(pos);
                return;
            }

            // foreach (var info in e.Result.ArmorDamageInfos) {
            //     DamageNumberProcess(new DamageInfo(info.Damage, e.Result.DamageType), pos);
            // }

            // DamageNumberProcess(new DamageInfo(e.Result.DamageMake, DamageType.Physic), pos);
            // // // 护甲破坏
            // if (e.Result.WillArmorBreak()) {
            //     armorBreakFeedback.PlayFeedbacks(pos);
            // }
            
            // 判断攻击轻重
            // var judgeFactor = e.Target.ComEquip.GetArmorPoint() + e.Target.CurHealth.Value;
            // if (e.Result.ActualDamageMake >= judgeFactor / 2) {
            //     hitHeavyFeedback.PlayFeedbacks(pos);
            // }
            // else {
            //     hitLightFeedback.PlayFeedbacks(pos);
            // }
            
            hitLightFeedback.PlayFeedbacks(pos);

            
            // 攻击额外粒子效果
            // if (e.Source.Model is HumanoidModel {weaponPivot: {} pivot} && pivot.CurWeapon) {
            //     foreach (var particle in pivot.CurWeapon.Particles) {
            //         if (particle == null) continue;
            //         var obj = Instantiate(particle);
            //         obj.transform.position = pos;
            //     }
            // }

            // var ability = CellGridSystem.Instance.CurAbilityPlaying;
            // if (ability?.Data.fxPlayer is not {hitFx: {}} fxPlayer) return;
            // foreach (var particle in fxPlayer.hitFx) {
            //     if (particle == null) continue;
            //     var obj = Instantiate(particle);
            //     obj.transform.position = pos;
            // }


            //
            // // 暴击反馈
            // if (e.Result.Critical) {
            //     criticalFeedback.PlayFeedbacks(pos);
            //     critical.Spawn(pos);
            // }
        }

        private void HealthLostFeedBack(UnitHealthLostEvent args) {
            if (!args.Unit) return;
            var pos = args.Unit.transform.position;
            healthDamageFeedback.SpawnText(pos, args.DamageInfo.Num);
        }



        private void DamageNumberProcess(DamageInfo info, Vector3 pos) {
            info.Num = Math.Max(0, info.Num);
            switch (info.Type) {
                case DamageType.Physic:
                    damageFeedback.SpawnText(pos, info.Num);
                    break;
                case DamageType.Heat:
                    fireDamage.SpawnText(pos, info.Num);
                    break;
                case DamageType.Electric:
                    electricDamage.SpawnText(pos, info.Num);
                    break;
                case DamageType.Acid:
                    acidDamage.SpawnText(pos, info.Num);
                    break;
                case DamageType.Basicity:
                    damageFeedback.SpawnText(pos, info.Num);
                    break;
                case DamageType.Pollution:
                    damageFeedback.SpawnText(pos, info.Num);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }



        private EventHandler _eventHandler = new();
        
        private void Start() {
            _eventHandler.UnRegisterAll();

            _eventHandler.RegisterEvent<UnitAttackResultEvent>(this.DamageFeedback);
            
            _eventHandler.RegisterEvent<UnitHealthLostEvent>(HealthLostFeedBack);
            
            _eventHandler.RegisterEvent<Event_Unit.Select>(OnUnitSelect);
            _eventHandler.RegisterEvent<WeaponChangeEvent>(OnUnitWeaponChange);
            _eventHandler.RegisterEvent<Event_Unit.BlockAttack>(OnUnitBlockAttack);

            _eventHandler.RegisterEvent<Event_Unit.Death>(OnUnitDeath);
        }

        private void OnDestroy()
        {
            _eventHandler.UnRegisterAll();
        }

        private void OnUnitBlockAttack(Event_Unit.BlockAttack obj) {
            blockAttackFeedback.PlayFeedbacks(obj.Unit.transform.position);
        }


        private void OnUnitSelect(Event_Unit.Select obj) {
            // WeaponChangeFeedBack(obj.Unit.ComEquip.CurWeapon.TypeCode);
        }
        
        

        private void OnUnitWeaponChange(WeaponChangeEvent obj) {
            WeaponChangeFeedBack(obj.Cur.TypeCode);
        }


        private void WeaponChangeFeedBack(WeaponTypeCode code) {
            if (code.IsRanged()) {
                onRangeTakeout.PlayFeedbacks();
            }
            else {
                onMeleeTakeout.PlayFeedbacks();
            }
        }


        private void OnUnitDeath(Event_Unit.Death obj) {
            var unit = obj.Unit;
            if (!unit) return;
            var pos = unit.transform.position;
            deathFeedback.PlayFeedbacks(pos);
        }
        
        
        public void PlayFloatingText(BaseUnit unit, string text) {
            if (unit == null) return;
            var txt = attackMiss.Spawn(unit.transform.position);
            txt.leftText = text;
        }


        // public void PlayBlockAttackEffect(BaseUnit unit) {
        //     if (unit == null) return;
        //     var pos = unit.transform.position;
        //     pos.y = CellGridSystem.Instance.PlaceHolder.transform.position.y;
        //     
        //     PlayFloatingText(unit, "格挡");
        //     if (blockAttackFeedback) {
        //         blockAttackFeedback.PlayFeedbacks(pos);
        //     }
        // }




        /// <returns> 效果持续时间 </returns>
        public float PlayFx(BaseUnit unit, FxCode fxCode) {
            if (unit == null || generalPlayer == null) return 0;
            
            return generalPlayer.Play(fxCode, SkillEntity.GroundPos(unit));
        }


        public static void PlayAbilityStartFx(BaseUnit unit) {
            // if (unit == null) return;
            //
            // var pos = unit.transform.position;
            // var ability = CellGridSystem.Instance.CurAbilityPlaying;
            // if (ability?.Data.fxPlayer is not {startFx: {}} fxPlayer) return;
            // foreach (var particle in fxPlayer.startFx) {
            //     if (particle == null) continue;
            //     var obj = Instantiate(particle);
            //     obj.transform.position = pos;
            // }

        }

        public void PlayFloatingText(BaseUnit unit, string text, Color color) {
        }
    }
}